package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.heima.api.ChannelFeignClient;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticleService;
import com.heima.common.constans.ArticleConstants;
import com.heima.model.article.dtos.HotArticleVo;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.mess.ArticleVisitStreamMess;
import com.heima.model.wemedia.pojos.WmChannel;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 热点文章业务接口
 */
@Service
public class HotArticleServiceImpl implements HotArticleService {
    @Autowired
    private ApArticleMapper apArticleMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ChannelFeignClient client;

    /**
     * 计算热点文章
     */
    @Override
    //加定时任务
    @XxlJob("HotArticleJobHandle")
    public void computeHotArticle() {
        //1.查询当前日期前五天的文章列表
        Calendar calendar=Calendar.getInstance();
        calendar.add(Calendar.DATE,-5 );
        Date last5Day=calendar.getTime();
        //第二种获取当前日期前五天的
        //Date date = DateTime.now().minusDays(5).toDate();
        List<ApArticle> apArticleList = apArticleMapper.loadArticleLast5DaysList(last5Day);

        //2.对这些文章进行分值计算
        List<HotArticleVo> hotArticleVoList=jisuanArticleScore(apArticleList);

        //3.根据频道，取出前三十条分值较高的文章存入到redis中
            //先远程调用频道列表
        ResponseResult<List<WmChannel>>responseResult = client.channels();
        if(responseResult.getCode()==200){
            List<WmChannel> channelsList = (List<WmChannel>) responseResult.getData();
            //检索出每个频道的文章
            for (WmChannel wmChannel : channelsList) {
                //根据频道获取的文章列表
                List<HotArticleVo> channelHotArtielcList = hotArticleVoList.stream().filter(hotArticleVo -> hotArticleVo.getChannelId() == wmChannel.getId()).collect(Collectors.toList());
                //根据时间降序排序
                cacheToRedis(channelHotArtielcList, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + wmChannel.getId());
            }
        }
        //4.推荐(全部文章),取出前三十条分值较高的文章存入到redis中
        //根据时间降序排序
        cacheToRedis(hotArticleVoList, ArticleConstants.HOT_ARTICLE_FIRST_PAGE+"__all__");
    }



    private void cacheToRedis(List<HotArticleVo> channelHotArtielcList, String key) {
        channelHotArtielcList = channelHotArtielcList.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed()).collect(Collectors.toList());
        //取出30条分值较高的文章列表，
        channelHotArtielcList = channelHotArtielcList.stream().limit(30).collect(Collectors.toList());
        //然后存入到redis中
        redisTemplate.opsForValue().set(key, JSON.toJSONString(channelHotArtielcList));
    }

    /**
     * 计算文章的分值
     * @param apArticleList
     * @return
     */
    private List<HotArticleVo> jisuanArticleScore(List<ApArticle> apArticleList) {
        List<HotArticleVo> hotArticleVoList=new ArrayList<>();
        //遍历list集合
        for (ApArticle apArticle : apArticleList) {
            HotArticleVo hotArticleVo=new HotArticleVo();
            BeanUtils.copyProperties(apArticle,hotArticleVo);
            //计算分值核心代码
           Integer score=computeArticleScore(apArticle);

            hotArticleVo.setScore(score);
            hotArticleVoList.add(hotArticleVo);
        }
        return hotArticleVoList;
    }

    /**
     * 计算分值的核心代码
     * @param apArticle
     * @return
     */
    private Integer computeArticleScore(ApArticle apArticle) {
        //声明一个变量
        Integer score=0;
        //点赞
        if(apArticle.getLikes()!=null){
            score+=apArticle.getLikes()* ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        //阅读
        if(apArticle.getViews()!=null){
            score+=apArticle.getViews();
        }
        //评论
        if(apArticle.getComment()!=null){
            score+=apArticle.getComment()*ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        //收藏
        if(apArticle.getCollection()!=null){
            score+=apArticle.getCollection()*ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }
        return score;
    }

    /**
     * 更新文章的分值  同时更新缓存中的热点文章数据
     *
     * @param mess
     */
    @Override
    public void updateScore(ArticleVisitStreamMess mess) {
        //1.修改ap_article表中的行为数量
        ApArticle apArticle = apArticleMapper.selectById(mess.getArticleId());
        if(apArticle==null){
            return;
        }
        apArticle.setCollection((apArticle.getCollection()==null?0:apArticle.getCollection())+mess.getCollect());
        apArticle.setComment((apArticle.getComment()==null?0:apArticle.getComment())+mess.getComment());
        apArticle.setLikes((apArticle.getLikes()==null?0:apArticle.getLikes())+mess.getLike());
        apArticle.setViews((apArticle.getViews()==null?0:apArticle.getViews())+mess.getView());
        apArticleMapper.updateById(apArticle);

        //2.重新计算分值
        Integer score = this.computeArticleScore(apArticle);
        score=score*3;
        //3.频道，替换redis中的数据
        replaceDataToRedis(apArticle, score,ArticleConstants.HOT_ARTICLE_FIRST_PAGE+ apArticle.getChannelId());

        //4.推荐(全部文章),替换redis中的数据
        replaceDataToRedis(apArticle, score,ArticleConstants.HOT_ARTICLE_FIRST_PAGE+"__all__");
    }

    private void replaceDataToRedis(ApArticle apArticle, Integer score,String key) {
        String hotArticleVoListStr = redisTemplate.opsForValue().get(key);
        if(StringUtils.isBlank(hotArticleVoListStr)){
            return;
        }
        //定义一个标识，true表示不存在，false表示存在
        boolean flag=true;

        List<HotArticleVo> hotArticleVoList = JSONArray.parseArray(hotArticleVoListStr, HotArticleVo.class);
        if(hotArticleVoList!=null && hotArticleVoList.size()>0){
            for (HotArticleVo hotArticleVo : hotArticleVoList) {
                //当前缓存中是否存在该文章,表示缓存存在
                if(hotArticleVo.getId().equals(apArticle.getId())){
                    hotArticleVo.setScore(score);
                    flag=false;
                    break;
                }
            }
            //缓存中不存在
            if(flag){
                //1.判断hotArticleVoList的长度是否大于30
                if(hotArticleVoList.size()>=30){
                    //1.1.如果大于30,倒叙展示
                    hotArticleVoList=hotArticleVoList.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed()).collect(Collectors.toList());
                    //1.2 取出最后一条
                    HotArticleVo lastHotArticleVo = hotArticleVoList.get(hotArticleVoList.size() - 1);
                    //1.3比大小
                    if(lastHotArticleVo.getScore()< score){
                        hotArticleVoList.remove(lastHotArticleVo);

                        HotArticleVo hotArticleVo=new HotArticleVo();
                        BeanUtils.copyProperties(apArticle,hotArticleVo);
                        hotArticleVo.setScore(score);
                        hotArticleVoList.add(hotArticleVo);
                    }
                }else{
                    //新数据
                    HotArticleVo hotArticleVo=new HotArticleVo();
                    BeanUtils.copyProperties(apArticle,hotArticleVo);
                    hotArticleVo.setScore(score);
                    hotArticleVoList.add(hotArticleVo);
                }

            }
            //重新排序
            hotArticleVoList=hotArticleVoList.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed()).collect(Collectors.toList());

            //都要封装数据到redis中
            redisTemplate.opsForValue().set(key,JSON.toJSONString(hotArticleVoList));
        }
    }
}
